Loan data

In this project we are analysing a dataset from the company Prosper, who is part of the peer-to-peer lending industry.

Univariate Plots Section

In this section we will preform prelaiminary exploration of the dataset to get an understanding ot the structure and the indivual variables in the loan dataset.

The loan orginial amount is the amount that was bid. The median of the loans is 6500. I suggest the money is needed for extra expenses due to unexpected problems, like home improvements or taking a small loan for a holiday. It seems the loans above 25000 are not often needed. So we will perform an outlier check.

There are 4395 outliers identified from the 113937 data objects. We will first replace the outliers with NA values and then create a new filtered data frame without the outliers.


Attaching package: 'dplyr'

The following object is masked from 'package:gridExtra':

    combine

The following objects are masked from 'package:stats':

    filter, lag

The following objects are masked from 'package:base':

    intersect, setdiff, setequal, union

The loan taker can choose between a 12, 36 or 60 month long term. In the plot above we can see that most of the loans are taken with a term of 36 month.

To get a better readability, we are going to map the numeric values to better readable strings according to this site: https://www.prosper.com/Downloads/Services/Documentation/ProsperDataExport_Details.html

As we can see in the plot above the most loans are needed for the categories “Debt Consolidation”, “Not Available” and “Other”. So it seems loan takers do not want to tell the purpose of their loans.

We will make another plot where we skip those categories, to take a closer look at the other categories.

Because there are 68 different types of occupation we are going to combine groups into a new data frame into bigger occupation groups.

Almost the same amount of loan takers ar home owners. Because we filtered out the top outliers from the loan original amount, we can see that slightly more non home owners need a loan.

The plot above shows that there is most of the data for credit grade missing.

We can see that the longer people have an employment the less they need a loan.

The majority of the Investors is just one person. In the plot above, we limit the number of loans given to 760 in order to get a better picture of loans given by more then one investor.

Univariate Analysis

Structure of the dataset

This data set contains 113,937 loans with 82 variables on each loan. Including loan amount, borrower rate (or interest rate), current loan status, borrower income, borrower employment status, borrower credit history, and the latest payment information. The explanation of the variables can be found there: https://www.prosper.com/Downloads/Services/Documentation/ProsperDataExport_Details.html

Main features of interest in the dataset

We want to know how much money is needed, when and why. So the most important variables are ‘OriginalLoanAmount’, ‘LoanOriginationDate’ and ‘Category’. We think it is also interesting to see if there is a difference in loan taking between home owners and non home owners. Then we are also interested to see if the credit grade and the prosper score are related to other variables.

More features

Another point of interest is the lender yield. And we are alos curious about the fees that the company takes.

New variables

To provide a better readability we created the variable “Category”, where we mapped the categories to the numbers of the ‘ListingCategory..numeric’. We also created a new variable named ‘GroupedOccupation’. Because the original variable ‘Occupation’ consits of 68 levels, we wanted to group those to get a better overview. The new variable consits of 8 levels representing our occupational groups.

Changed variables

In the LoanOriginalAmount variable we perforemed an outlier check and removed those values in order to make the following analysis more robust.

Bivariate Plots Section

No we want to take a look at the home owners. In the next step we want to proof that people who aren t home owners need more often small loans for vacation, home improvement or household expenses than home owners. Our suggestion that house owners need less loans, seem to be wrong. Almost half the amount of borrowers are house owners. We limit the loan amount to a smaller range, because we want to know if house owners also need smaller loans, for home improvments or others.

In the plot above we can see that house owners need bigger amounts of money than non house owners.

Next we want to see, if there is a relation between the prosper rate and the fact that the borrower is a house owner. Normally a house owner has a better rating, due to more financial security.

Another surprise here. The Prosper score for non home owners is just a little bit lower.

In the plot above we can not notice any difference between home owners and non home owners in current delinquencies.

No surprises here, the better the Prosper Score, the better the borrower rate.

We suggest that the prosper rating is better if the income is verifiable.

Yes, our suggestion is right.

As we can see in the plot above, the better the credit grade, less delinquenices.

The majority of the loan takers are full time employees. The worse the credit grade gets the more likely the employment status is “not available”. We exclude missing data in our plot, to get a good picture.

We suggest that there is a higher lender yield, if the borrower rate is higher.

Yes, we can see clearly the higher the borrower rate, the higher the lender yield.

Bivariate Analysis

We found out that there is almost no difference between home owners and non home owners by prosper score and delinquencies. There is a slight difference as home owners tend to need bigger loans.

The prosper rating is better if the income is verifiable. The worse the credit grade the more often occured delinquencies in the last 7 years.

We notice a strong relation between the lender yield and the borrower rate. The higher the borrower rate, the better the lender yield.

Multivariate Plots Section

In the plot above we can see that from 2006 to 2010 the loans where taken for 36 month. Maybe back than this was the only term available. From 2010 on if the loan amount was higher borrowers selected the 60 month term. In 2011 the loans increased a lot.

In the factor plot above, we can see that students need the smaller amounts of money. The higher the loan gets, the more homeowners are the borrowers.

In the plot above we can see that most of the loans are mid-term.

In the plot above we can see quite well, that the investors yield gets higher the higher the borrower rate gets.

The plot above gives us a nice overview. As we can see most of the loans are mid term loans with a duration of 36 month. The usages of the loans are well mixed.

The plot above gives an overview of the estimated return and estimated loss by grouped occupation and income range. As there is to much information in the plot, we hardly can see anything. So we are going to split this into two plots.

The plots above are still not readable. So in the next plot we want to focus on on specific occupation group and the estimated losses and returns.

This plot shows that the lower the customer payments are the lower the service fees and interest fees are.

In the plot above we get an overview of the loans by category and grouped occupation. It is quite hard to find a pattern on the first sight, so maybe a normal list would have done a better job.

Multivariate Analysis

Estimated loss and estimated return by income range and grouped occupation

We ploted an overview of the estimated return and the estimated loss by grouped occupation and income range. Because the plot was to dense and unreadable, we split it up into two plots. One for the income range and one for the occupation group. But this plot is not very readable either. So we focused on one occupationl group - the students. This plot is well readable. And it was quite surprising that there is one outlier with a negative estimated return and a really high estimated loss. ### Heatmap of grouped occupation and category by loan original amount It was expected that this heatmap gives a nive overview of the occupations and categories. We were hoping to find patterns with one look. But this is not the case, you have to elaborate this plot. Maybe it would have been better to provide a list in this case. ### Loans and Fees From 2006 to 2010 the loans where taken for 36 month. Maybe back than this was the only term available. From 2010 on if the loan amount was higher borrowers selected the 60 month term. In 2011 the loans increased a lot. We found out that the lower the customer payments are the lower the service fees and interest fees are. Which is not a surprise.

Final Plots and Summary

Loan amount by grouped occupation and homeowner status

Description

In the factor plot above, we can see that students need the smaller amounts of money. Surprisingly there are a lot of home owners in the group student. The higher the loan gets, the more homeowners are the borrowers. In some occupational groups there are a lot more home owners. This may be caused by our occupational grouping, which contains professions with a wide income range. For example in the group ‘Medical_Health’, there are doctors and nurses etc.

Histogram of loan amounts by term and loan status

Description

In the plot above we can see that most of the plots are taken with a terma of 36 month. Even though the amounts are not that big. This may be because until 2009 there where only loans with a term of 36 month. This may also explain why the loan status is completed or charged off for the most of the loans under 5000. We can also see that short term loans are not often used at the moment. People prefer mid or long term loans.

Estimated return and estimated loss for students

Description

We can see that most of the students earn between $1- 24,999. There are some students that a earn more than $75,000. There are some outliers where the estimated loss is higher than the estimated return. The majority of the estimated returns and estimated losses are betw depending on the income range of a student are between 0.05 and 0.15. Surprisingly there is one outlier with a negative estimated return and a really high estimated loss.

Summary

Because of the big amount of variables it took some time, to read through the explanations of the prosper loan data. To get started we explored some different variables. In order to get nice plots, we had to convert some values. For example the origin date to year, the numeric categories into readable categories and the job duration months where summarized in buckets It was interresting to see that from 2011 on borrowers needed higher loans with longer terms. It was quite a surprise that there is no big difference between home owners and non home owners, because we suggested that home owners are financially more strong and don’t need small loans. For the other variables I could not find a lot of surprising facts. For example the worse the credit grade is, the higher the delinquencies in the last 7 years are or that the lender yield gets lower the higher the numbe of investors get. It would be nice if there were not big groups like ‘na’ or ‘other’ in the occupation and category group. Maybe there could be also data about the age and gender of the borrower provided, which may lead to interesting findings.

LS0tCnRpdGxlOiAiRURBIGZvciBMb2FuIERhdGEgYnkgQmFyYmFyYSBKb2Vic3RsIgotLS0KCmBgYHtyLCBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWNrYWdlc30KbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGdyaWRFeHRyYSkKbGlicmFyeShkcGx5cikKYGBgCgoKYGBge3IsIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxvYW5zIDwtIHJlYWQuY3N2KCdwcm9zcGVybG9hbkRhdGEuY3N2JykKaGVhZChsb2FucykKYGBgCgojTG9hbiBkYXRhCkluIHRoaXMgcHJvamVjdCB3ZSBhcmUgYW5hbHlzaW5nIGEgZGF0YXNldCBmcm9tIHRoZSBjb21wYW55IFByb3NwZXIsIHdobyBpcyBwYXJ0IG9mIHRoZSBwZWVyLXRvLXBlZXIgbGVuZGluZyBpbmR1c3RyeS4KCiMgVW5pdmFyaWF0ZSBQbG90cyBTZWN0aW9uCkluIHRoaXMgc2VjdGlvbiB3ZSB3aWxsIHByZWZvcm0gcHJlbGFpbWluYXJ5IGV4cGxvcmF0aW9uIG9mCnRoZSBkYXRhc2V0IHRvIGdldCBhbiB1bmRlcnN0YW5kaW5nIG90IHRoZSBzdHJ1Y3R1cmUgYW5kIHRoZSBpbmRpdnVhbCB2YXJpYWJsZXMgaW4gdGhlIGxvYW4gZGF0YXNldC4KCmBgYHtyLCBlY2hvPUZBTFNFLCBVbml2YXJpYXRlX1Bsb3RfMSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZ2dwbG90KGFlcyh4ID0gTG9hbk9yaWdpbmFsQW1vdW50KSwgZGF0YSA9IGxvYW5zKSArIAogIGdlb21faGlzdG9ncmFtKGNvbG9yID0gKCcjMjQzMjNlJyksIGZpbGwgPSAoJyMwMmNjYmEnKSkgKwogIGdndGl0bGUoJ0hpc3RvZ3JhbSBvZiBvcmlnaW5hbCBsb2FuIGFtb3VudCcpCgpzdW1tYXJ5KGxvYW5zJExvYW5PcmlnaW5hbEFtb3VudCkKYGBgCgpUaGUgbG9hbiBvcmdpbmlhbCBhbW91bnQgaXMgdGhlIGFtb3VudCB0aGF0IHdhcyBiaWQuClRoZSBtZWRpYW4gb2YgdGhlIGxvYW5zIGlzIDY1MDAuIEkgc3VnZ2VzdCB0aGUgbW9uZXkgaXMgbmVlZGVkIGZvciBleHRyYSBleHBlbnNlcyBkdWUgdG8gdW5leHBlY3RlZCBwcm9ibGVtcywgbGlrZSBob21lIGltcHJvdmVtZW50cyBvciB0YWtpbmcgYSBzbWFsbCBsb2FuIGZvciBhIGhvbGlkYXkuIEl0IHNlZW1zIHRoZSBsb2FucyBhYm92ZSAyNTAwMCBhcmUgbm90IG9mdGVuIG5lZWRlZC4gU28gd2Ugd2lsbCBwZXJmb3JtIGFuIG91dGxpZXIgY2hlY2suCgpgYGB7ciwgZWNobz1GQUxTRSwgVW5pdmFyaWF0ZV9QbG90XzIsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9Cgojc2NyaXB0IHRvIGRldGVjdCBvdXRsaWVycyAtIHNvdXJjZTogaHR0cHM6Ly93d3cuci1ibG9nZ2Vycy5jb20vaWRlbnRpZnktZGVzY3JpYmUtcGxvdC1hbmQtcmVtb3ZlLXRoZS1vdXRsaWVycy1mcm9tLXRoZS1kYXRhc2V0LwpvdXRsaWVyS0QgPC0gZnVuY3Rpb24oZHQsIHZhcikgewogICAgIHZhcl9uYW1lIDwtIGV2YWwoc3Vic3RpdHV0ZSh2YXIpLGV2YWwoZHQpKQogICAgIG5hMSA8LSBzdW0oaXMubmEodmFyX25hbWUpKQogICAgIG0xIDwtIG1lYW4odmFyX25hbWUsIG5hLnJtID0gVCkKICAgICBwYXIobWZyb3c9YygyLCAyKSwgb21hPWMoMCwwLDMsMCkpCiAgICAgYm94cGxvdCh2YXJfbmFtZSwgbWFpbj0iV2l0aCBvdXRsaWVycyIpCiAgICAgaGlzdCh2YXJfbmFtZSwgbWFpbj0iV2l0aCBvdXRsaWVycyIsIHhsYWI9TkEsIHlsYWI9TkEpCiAgICAgb3V0bGllciA8LSBib3hwbG90LnN0YXRzKHZhcl9uYW1lKSRvdXQKICAgICBtbyA8LSBtZWFuKG91dGxpZXIpCiAgICAgdmFyX25hbWUgPC0gaWZlbHNlKHZhcl9uYW1lICVpbiUgb3V0bGllciwgTkEsIHZhcl9uYW1lKQogICAgIGJveHBsb3QodmFyX25hbWUsIG1haW49IldpdGhvdXQgb3V0bGllcnMiKQogICAgIGhpc3QodmFyX25hbWUsIG1haW49IldpdGhvdXQgb3V0bGllcnMiLCB4bGFiPU5BLCB5bGFiPU5BKQogICAgIHRpdGxlKCJPdXRsaWVyIENoZWNrIiwgb3V0ZXI9VFJVRSkKICAgICBuYTIgPC0gc3VtKGlzLm5hKHZhcl9uYW1lKSkKICAgICBjYXQoIk91dGxpZXJzIGlkZW50aWZpZWQ6IiwgbmEyIC0gbmExLCAibiIpCiAgICAgY2F0KCJQcm9wb3Rpb24gKCUpIG9mIG91dGxpZXJzOiIsIHJvdW5kKChuYTIgLSBuYTEpIC8gc3VtKCFpcy5uYSh2YXJfbmFtZSkpKjEwMCwgMSksICJuIikKICAgICBjYXQoIk1lYW4gb2YgdGhlIG91dGxpZXJzOiIsIHJvdW5kKG1vLCAyKSwgIm4iKQogICAgIG0yIDwtIG1lYW4odmFyX25hbWUsIG5hLnJtID0gVCkKICAgICBjYXQoIk1lYW4gd2l0aG91dCByZW1vdmluZyBvdXRsaWVyczoiLCByb3VuZChtMSwgMiksICJuIikKICAgICBjYXQoIk1lYW4gaWYgd2UgcmVtb3ZlIG91dGxpZXJzOiIsIHJvdW5kKG0yLCAyKSwgIm4iKQogICAgIHJlc3BvbnNlIDwtIHJlYWRsaW5lKHByb21wdD0iRG8geW91IHdhbnQgdG8gcmVtb3ZlIG91dGxpZXJzIGFuZCB0byByZXBsYWNlIHdpdGggTkE/IFt5ZXMvbm9dOiAiKQogICAgIGlmKHJlc3BvbnNlID09ICJ5IiB8IHJlc3BvbnNlID09ICJ5ZXMiKXsKICAgICAgICAgIGR0W2FzLmNoYXJhY3RlcihzdWJzdGl0dXRlKHZhcikpXSA8LSBpbnZpc2libGUodmFyX25hbWUpCiAgICAgICAgICBhc3NpZ24oYXMuY2hhcmFjdGVyKGFzLmxpc3QobWF0Y2guY2FsbCgpKSRkdCksIGR0LCBlbnZpciA9IC5HbG9iYWxFbnYpCiAgICAgICAgICBjYXQoIk91dGxpZXJzIHN1Y2Nlc3NmdWxseSByZW1vdmVkIiwgIm4iKQogICAgICAgICAgcmV0dXJuKGludmlzaWJsZShkdCkpCiAgICAgfSBlbHNlewogICAgICAgICAgY2F0KCJOb3RoaW5nIGNoYW5nZWQiLCAibiIpCiAgICAgICAgICByZXR1cm4oaW52aXNpYmxlKHZhcl9uYW1lKSkKICAgICB9Cn0KCm91dGxpZXJLRChsb2FucywgTG9hbk9yaWdpbmFsQW1vdW50KQpgYGAKClRoZXJlIGFyZSA0Mzk1IG91dGxpZXJzIGlkZW50aWZpZWQgZnJvbSB0aGUgMTEzOTM3IGRhdGEgb2JqZWN0cy4gV2Ugd2lsbCBmaXJzdCByZXBsYWNlIHRoZSBvdXRsaWVycyB3aXRoIE5BIHZhbHVlcyBhbmQgdGhlbiBjcmVhdGUgYSBuZXcgZmlsdGVyZWQgZGF0YSBmcmFtZSB3aXRob3V0IHRoZSBvdXRsaWVycy4KCmBgYHtyLCBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpsb2Fuc19maWx0ZXJlZCA8LSBsb2Fuc1shd2l0aChsb2Fucyxpcy5uYShMb2FuT3JpZ2luYWxBbW91bnQpKSxdCmBgYAoKYGBge3IsIGVjaG89RkFMU0UsIFVuaXZhcmlhdGVfUGxvdF8zfQpnZ3Bsb3QoYWVzKHggPSBUZXJtKSwgZGF0YSA9IGxvYW5zX2ZpbHRlcmVkKSArIAogIGdlb21faGlzdG9ncmFtKGNvbG9yID0gKCcjMjQzMjNlJyksIGZpbGwgPSAoJyMwMmNjYmEnKSkgKwogIGdndGl0bGUoJ1Rlcm1zIGluIG1vbnRoJykKCnN1bW1hcnkobG9hbnMkVGVybSkKYGBgCgpUaGUgbG9hbiB0YWtlciBjYW4gY2hvb3NlIGJldHdlZW4gYSAxMiwgMzYgb3IgNjAgbW9udGggbG9uZyB0ZXJtLiBJbiB0aGUgcGxvdCBhYm92ZSB3ZSBjYW4gc2VlIHRoYXQgbW9zdCBvZiB0aGUgbG9hbnMgYXJlIHRha2VuIHdpdGggYSB0ZXJtIG9mIDM2IG1vbnRoLgoKVG8gZ2V0IGEgYmV0dGVyIHJlYWRhYmlsaXR5LCB3ZSBhcmUgZ29pbmcgdG8gbWFwIHRoZSBudW1lcmljIHZhbHVlcyB0byBiZXR0ZXIgcmVhZGFibGUgc3RyaW5ncyBhY2NvcmRpbmcgdG8gdGhpcyBzaXRlOiBodHRwczovL3d3dy5wcm9zcGVyLmNvbS9Eb3dubG9hZHMvU2VydmljZXMvRG9jdW1lbnRhdGlvbi9Qcm9zcGVyRGF0YUV4cG9ydF9EZXRhaWxzLmh0bWwKCmBgYHtyLCBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojdHJhbnNmb3JtIHRoZSBudW1lcmljIHZhbHVlIG9mIGNhdGVnb3JpZXMgdG8gcmVhZGFibGUgbmFtZXMtLS0tLS0tLS0tLS0tLQpsb2Fuc19maWx0ZXJlZCRDYXRlZ29yeVtsb2Fuc19maWx0ZXJlZCRMaXN0aW5nQ2F0ZWdvcnkuLm51bWVyaWMuID09ICcwJ10gPC0gJ05vdCBBdmFpbGFibGUnCmxvYW5zX2ZpbHRlcmVkJENhdGVnb3J5W2xvYW5zX2ZpbHRlcmVkJExpc3RpbmdDYXRlZ29yeS4ubnVtZXJpYy4gPT0gJzEnXSA8LSAnRGVidCBDb25zb2xpZGF0aW9uJwpsb2Fuc19maWx0ZXJlZCRDYXRlZ29yeVtsb2Fuc19maWx0ZXJlZCRMaXN0aW5nQ2F0ZWdvcnkuLm51bWVyaWMuID09ICcyJ10gPC0gJ0hvbWUgSW1wcm92ZW1lbnQnCmxvYW5zX2ZpbHRlcmVkJENhdGVnb3J5W2xvYW5zX2ZpbHRlcmVkJExpc3RpbmdDYXRlZ29yeS4ubnVtZXJpYy4gPT0gJzMnXSA8LSAnQnVzaW5lc3MnCmxvYW5zX2ZpbHRlcmVkJENhdGVnb3J5W2xvYW5zX2ZpbHRlcmVkJExpc3RpbmdDYXRlZ29yeS4ubnVtZXJpYy4gPT0gJzQnXSA8LSAnUGVyc29uYWwgTG9hbicKbG9hbnNfZmlsdGVyZWQkQ2F0ZWdvcnlbbG9hbnNfZmlsdGVyZWQkTGlzdGluZ0NhdGVnb3J5Li5udW1lcmljLiA9PSAnNSddIDwtICdTdHVkZW50IFVzZScKbG9hbnNfZmlsdGVyZWQkQ2F0ZWdvcnlbbG9hbnNfZmlsdGVyZWQkTGlzdGluZ0NhdGVnb3J5Li5udW1lcmljLiA9PSAnNiddIDwtICdBdXRvJwpsb2Fuc19maWx0ZXJlZCRDYXRlZ29yeVtsb2Fuc19maWx0ZXJlZCRMaXN0aW5nQ2F0ZWdvcnkuLm51bWVyaWMuID09ICc3J10gPC0gJ090aGVyJwpsb2Fuc19maWx0ZXJlZCRDYXRlZ29yeVtsb2Fuc19maWx0ZXJlZCRMaXN0aW5nQ2F0ZWdvcnkuLm51bWVyaWMuID09ICc4J10gPC0gJ0JhYnkgJiBBZG9wdGlvbicKbG9hbnNfZmlsdGVyZWQkQ2F0ZWdvcnlbbG9hbnNfZmlsdGVyZWQkTGlzdGluZ0NhdGVnb3J5Li5udW1lcmljLiA9PSAnOSddIDwtICdCb2F0Jwpsb2Fuc19maWx0ZXJlZCRDYXRlZ29yeVtsb2Fuc19maWx0ZXJlZCRMaXN0aW5nQ2F0ZWdvcnkuLm51bWVyaWMuID09ICcxMCddIDwtICdDb3NtZXRpYyBQcm9jZWR1cmUnCmxvYW5zX2ZpbHRlcmVkJENhdGVnb3J5W2xvYW5zX2ZpbHRlcmVkJExpc3RpbmdDYXRlZ29yeS4ubnVtZXJpYy4gPT0gJzExJ10gPC0gJ0VuZ2FnZW1lbnQgUmluZycKbG9hbnNfZmlsdGVyZWQkQ2F0ZWdvcnlbbG9hbnNfZmlsdGVyZWQkTGlzdGluZ0NhdGVnb3J5Li5udW1lcmljLiA9PSAnMTInXSA8LSAnR3JlZW4gTG9hbnMnCmxvYW5zX2ZpbHRlcmVkJENhdGVnb3J5W2xvYW5zX2ZpbHRlcmVkJExpc3RpbmdDYXRlZ29yeS4ubnVtZXJpYy4gPT0gJzEzJ10gPC0gJ0hvdXNlaG9sZCBFeHBlbnNlcycKbG9hbnNfZmlsdGVyZWQkQ2F0ZWdvcnlbbG9hbnNfZmlsdGVyZWQkTGlzdGluZ0NhdGVnb3J5Li5udW1lcmljLiA9PSAnMTQnXSA8LSAnTGFyZ2UgUHVyY2hhc2VzJwpsb2Fuc19maWx0ZXJlZCRDYXRlZ29yeVtsb2Fuc19maWx0ZXJlZCRMaXN0aW5nQ2F0ZWdvcnkuLm51bWVyaWMuID09ICcxNSddIDwtICdNZWRpY2FsL0RlbnRhbCcKbG9hbnNfZmlsdGVyZWQkQ2F0ZWdvcnlbbG9hbnNfZmlsdGVyZWQkTGlzdGluZ0NhdGVnb3J5Li5udW1lcmljLiA9PSAnMTYnXSA8LSAnTW90b3JjeWNsZScKbG9hbnNfZmlsdGVyZWQkQ2F0ZWdvcnlbbG9hbnNfZmlsdGVyZWQkTGlzdGluZ0NhdGVnb3J5Li5udW1lcmljLiA9PSAnMTcnXSA8LSAnUlYnCmxvYW5zX2ZpbHRlcmVkJENhdGVnb3J5W2xvYW5zX2ZpbHRlcmVkJExpc3RpbmdDYXRlZ29yeS4ubnVtZXJpYy4gPT0gJzE4J10gPC0gJ1RheGVzJwpsb2Fuc19maWx0ZXJlZCRDYXRlZ29yeVtsb2Fuc19maWx0ZXJlZCRMaXN0aW5nQ2F0ZWdvcnkuLm51bWVyaWMuID09ICcxOSddIDwtICdWYWNhdGlvbicKbG9hbnNfZmlsdGVyZWQkQ2F0ZWdvcnlbbG9hbnNfZmlsdGVyZWQkTGlzdGluZ0NhdGVnb3J5Li5udW1lcmljLiA9PSAnMjAnXSA8LSAnV2VkZGluZyBMb2FucycKYGBgCgpgYGB7ciwgZWNobz1GQUxTRSwgVW5pdmFyaWF0ZV9QbG90c180LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpyZW9yZGVyX3NpemUgPC0gZnVuY3Rpb24oeCkgewogIGZhY3Rvcih4LCBsZXZlbHMgPSBuYW1lcyhzb3J0KHRhYmxlKHgpKSkpCn0KCmdncGxvdChkYXRhID0gbG9hbnNfZmlsdGVyZWQsCiAgICAgICBhZXMocmVvcmRlcl9zaXplKENhdGVnb3J5KSkpICsKICAgICAgZ2VvbV9iYXIoY29sb3VyPScjMjQzMjNlJywgZmlsbD0nIzAyY2NiYScpKwogICAgICBnZ3RpdGxlKCJBbW91bnQgb2YgbG9hbnMgYnkgY2F0ZWdvcnkiKSArCiAgICAgIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT00NSxoanVzdD0xLHZqdXN0PTAuNSkpKwogICAgICBsYWJzKHg9IiIsIHkgPSAiTnVtYmVyIG9mIGxvYW5zIikgKwogICAgICBjb29yZF9mbGlwKCkKYGBgCgpBcyB3ZSBjYW4gc2VlIGluIHRoZSBwbG90IGFib3ZlIHRoZSBtb3N0IGxvYW5zIGFyZSBuZWVkZWQgZm9yIHRoZSBjYXRlZ29yaWVzICJEZWJ0IENvbnNvbGlkYXRpb24iLCAiTm90IEF2YWlsYWJsZSIgYW5kICJPdGhlciIuIFNvIGl0IHNlZW1zIGxvYW4gdGFrZXJzIGRvIG5vdCB3YW50IHRvIHRlbGwgdGhlIHB1cnBvc2Ugb2YgdGhlaXIgbG9hbnMuCgpXZSB3aWxsIG1ha2UgYW5vdGhlciBwbG90IHdoZXJlIHdlIHNraXAgdGhvc2UgY2F0ZWdvcmllcywgdG8gdGFrZSBhIGNsb3NlciBsb29rIGF0IHRoZSBvdGhlciBjYXRlZ29yaWVzLgoKYGBge3IsIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnJlb3JkZXJfc2l6ZSA8LSBmdW5jdGlvbih4KSB7CiAgZmFjdG9yKHgsIGxldmVscyA9IG5hbWVzKHNvcnQodGFibGUoeCkpKSkKfQoKZ2dwbG90KGRhdGEgPSBzdWJzZXQobG9hbnNfZmlsdGVyZWQsCiAgICAgICAgICAgICAgICAgICAgTG9hbk9yaWdpbmFsQW1vdW50ID4gMjUwMAogICAgICAgICAgICAgICAgICAgICYgTG9hbk9yaWdpbmFsQW1vdW50IDw9IDkwMDAKICAgICAgICAgICAgICAgICAgICAmIENhdGVnb3J5ICE9ICdEZWJ0IENvbnNvbGlkYXRpb24nCiAgICAgICAgICAgICAgICAgICAgJiBDYXRlZ29yeSAhPSAnTm90IEF2YWlsYWJsZScKICAgICAgICAgICAgICAgICAgICAmIENhdGVnb3J5ICE9ICdPdGhlcicpLAogICAgICAgYWVzKHJlb3JkZXJfc2l6ZShDYXRlZ29yeSkpKSArCiAgICAgIGdlb21fYmFyKGNvbG91cj0nIzI0MzIzZScsIGZpbGw9JyMwMmNjYmEnKSsKICAgICAgZ2d0aXRsZSgiQW1vdW50IG9mIGxvYW5zIGJ5IGNhdGVnb3J5IHdpdGhvdXQgJ09USEVSJyIpICsKICAgICAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LGhqdXN0PTEsdmp1c3Q9MC41KSkgKwogICAgICBsYWJzKHg9IiIsIHkgPSAiTnVtYmVyIG9mIGxvYW5zIikgKwogICAgICBjb29yZF9mbGlwKCkKYGBgCgpgYGB7ciwgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KaGVhZChsb2Fuc19maWx0ZXJlZCRPY2N1cGF0aW9uKQpgYGAKCkJlY2F1c2UgdGhlcmUgYXJlIDY4IGRpZmZlcmVudCB0eXBlcyBvZiBvY2N1cGF0aW9uIHdlIGFyZSBnb2luZyB0byBjb21iaW5lIGdyb3VwcyBpbnRvIGEgbmV3IGRhdGEgZnJhbWUgaW50byBiaWdnZXIgb2NjdXBhdGlvbiBncm91cHMuCgpgYGB7ciwgZWNobz1GQUxTRSwgVW5pdmFyaWF0ZV9QbG90c181LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojc3VtbWFyaXplIGRpZmZlcmVudCBvY2N1cGF0aW9ucyBpbnRvIGdyb3VwZWQgb2NjdXBhdGlvbnMtLS0tLS0tLS0tLS0tLS0tCmxvYW5zX2ZpbHRlcmVkJEdyb3VwZWRPY2N1cGF0aW9uIDwtIGZhY3Rvcihsb2Fuc19maWx0ZXJlZCRPY2N1cGF0aW9uKQpsZXZlbHMobG9hbnNfZmlsdGVyZWQkR3JvdXBlZE9jY3VwYXRpb24pIDwtIGxpc3QoCiAgU3R1ZGVudD1jKCJTdHVkZW50IC0gQ29sbGVnZSBHcmFkdWF0ZSBTdHVkZW50IiwKIlN0dWRlbnQgLSBDb2xsZWdlIFNlbmlvciIsIAoiU3R1ZGVudCAtIENvbW11bml0eSBDb2xsZWdlIiwKIlN0dWRlbnQgLSBDb2xsZWdlIEZyZXNobWFuIiwKIlN0dWRlbnQgLSBDb2xsZWdlIEp1bmlvciIsCiJTdHVkZW50IC0gQ29sbGVnZSBTb3Bob21vcmUiLAoiU3R1ZGVudCAtIFRlY2huaWNhbCBTY2hvb2wiKSwgCk1lZGljYWxfSGVhbHRoPWMoIkRvY3RvciIsICJOdXJzZSdzIEFpZGUiLAogICAgICAgICAgICAgICAgICJOdXJzZSAoUk4pIiwKICAgICAgICAgICAgICAgICAiTnVyc2UgKExQTikiLAogICAgICAgICAgICAgICAgICJEZW50aXN0IiwKICAgICAgICAgICAgICAgICAiUGhhcm1hY2lzdCIsCiAgICAgICAgICAgICAgICAgIk1lZGljYWwgVGVjaG5pY2lhbiIsCiAgICAgICAgICAgICAgICAgIlBzeWNob2xvZ2lzdCIpLApTYWxlcz1jKCJTYWxlcyAtIENvbW1pc3Npb24iLAogICAgICAgICJTYWxlcyAtIFJldGFpbCIsCiAgICAgICAgIkNhciBEZWFsZXIiLAogICAgICAgICJSZWFsdG9yIiksClNlcnZpY2U9YygiRm9vZCBTZXJ2aWNlIE1hbmFnZW1lbnQiLAogICAgICAgICAgIkZvb2QgU2VydmljZSIsCiAgICAgICAgICAiUG9zdGFsIFNlcnZpY2UiLAogICAgICAgICAgIlNvY2lhbCBXb3JrZXIiLAogICAgICAgICAgIlRydWNrIERyaXZlciIsCiAgICAgICAgICAiQnVzIERyaXZlciIsCiAgICAgICAgICAiUmV0YWlsIE1hbmFnZW1lbnQiLAogICAgICAgICAgIldhaXRlci9XYWl0cmVzcyIsCiAgICAgICAgICAiRmxpZ2h0IEF0dGVuZGFudCIsCiAgICAgICAgICAiQ2xlcmljYWwiLAogICAgICAgICAgIlJlbGlnaW91cyIsCiAgICAgICAgICAiQ2xlcmd5IiksCkxhYm9yZXI9YygiQ29uc3RydWN0aW9uIiwKICAgICAgICAgICJMYWJvcmVyIiwKICAgICAgICAgICJTa2lsbGVkIExhYm9yIiwKICAgICAgICAgICJMYW5kc2NhcGluZyIsCiAgICAgICAgICAiSG9tZW1ha2VyIiwKICAgICAgICAgICJGaXJlbWFuIiwKICAgICAgICAgICJFeGVjdXRpdmUiLAogICAgICAgICAgIlRlYWNoZXIncyBBaWRlIiwKICAgICAgICAgICJDb21wdXRlciBQcm9ncmFtbWVyIiwKICAgICAgICAgICJBZG1pbmlzdHJhdGl2ZSBBc3Npc3RhbnQiLAogICAgICAgICAgIlByb2Zlc3Npb25hbCIsCiAgICAgICAgICAiQWNjb3VudGFudC9DUEEiLAogICAgICAgICAgIlRyYWRlc21hbiAtIENhcnBlbnRlciIsCiAgICAgICAgICAgICJUcmFkZXNtYW4gLSBNZWNoYW5pYyIsCiAgICAgICAgICAgICJUcmFkZXNtYW4gLSBFbGVjdHJpY2lhbiIsCiAgICAgICAgICAgICJUcmFkZXNtYW4gLSBQbHVtYmVyIiwKICAgICAgICAgICJQaWxvdCAtIFByaXZhdGUvQ29tbWVyY2lhbCIpLApIaWdoZXJFZEpvYnM9YygiQXJjaGl0ZWN0IiwKICAgICAgICAgICAgICAgIkJpb2xvZ2lzdCIsCiAgICAgICAgICAgICAgICJFbmdpbmVlciAtIEVsZWN0cmljYWwiLAogICAgICAgICAgICAgICAiRW5naW5lZXIgLSBNZWNoYW5pY2FsIiwKICAgICAgICAgICAgICAgIkVuZ2luZWVyIC0gQ2hlbWljYWwiLAogICAgICAgICAgICAgICAiSnVkZ2UiLCAiVGVhY2hlciIsCiAgICAgICAgICAgICAgICJTY2llbnRpc3QiLAogICAgICAgICAgICAgICAiUHJvZmVzc29yIiwKICAgICAgICAgICAgICAgIkF0dG9ybmV5IiwgIkFuYWx5c3QiLCAiQWNjb3VudGFudC9DUEEiCiAgICAgICAgICAgICAgICksCkNpdmlsU2VydmljZT1jKCJDaXZpbCBTZXJ2aWNlIiwKICAgICAgICAgICAgICAgIk1pbGl0YXJ5IE9mZmljZXIiLAogICAgICAgICAgICAgICAiUG9saWNlIE9mZmljZXIvQ29ycmVjdGlvbiBPZmZpY2VyIiwKICAgICAgICAgICAgICAgIk1pbGl0YXJ5IEVubGlzdGVkIiksCk90aGVyPWMoIk90aGVyIiwgIiIpCikKCmdncGxvdChkYXRhPXN1YnNldChsb2Fuc19maWx0ZXJlZCwgR3JvdXBlZE9jY3VwYXRpb24gIT0gJ090aGVyJyAmICFpcy5uYShHcm91cGVkT2NjdXBhdGlvbikpLCB4PUdyb3VwZWRPY2N1cGF0aW9uLCBhZXMocmVvcmRlcl9zaXplKEdyb3VwZWRPY2N1cGF0aW9uKSkpICsKICAgIGdlb21fYmFyKGNvbG91cj0nIzI0MzIzZScsIGZpbGw9JyMwMmNjYmEnKSsKICAgIGdndGl0bGUoIkJvcnJvd2VycyBieSBPY2N1cGF0aW9uIikgKwogICAgbGFicyh4PSIiLCB5ID0gIk51bWJlciBvZiBsb2FucyIpICsKICAgIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT00NSxoanVzdD0xLHZqdXN0PTAuNSkpCmBgYAoKCmBgYHtyLCBlY2hvPUZBTFNFLCBVbml2YXJpYXRlX1Bsb3RzXzYsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmdncGxvdChhZXMoeCA9IElzQm9ycm93ZXJIb21lb3duZXIpLCBkYXRhID0gbG9hbnNfZmlsdGVyZWQpICsgCiAgZ2VvbV9iYXIoY29sb3IgPSAoJyMyNDMyM2UnKSwgZmlsbCA9ICgnIzAyY2NiYScpKSArCiAgZ2d0aXRsZSgnSG9tZSBvd25lcicpCgpzdW1tYXJ5KGxvYW5zX2ZpbHRlcmVkJElzQm9ycm93ZXJIb21lb3duZXIpCmBgYAoKQWxtb3N0IHRoZSBzYW1lIGFtb3VudCBvZiBsb2FuIHRha2VycyBhciBob21lIG93bmVycy4gQmVjYXVzZSB3ZSBmaWx0ZXJlZCBvdXQgdGhlIHRvcCBvdXRsaWVycyBmcm9tIHRoZSBsb2FuIG9yaWdpbmFsIGFtb3VudCwgd2UgY2FuIHNlZSB0aGF0IHNsaWdodGx5IG1vcmUgbm9uIGhvbWUgb3duZXJzIG5lZWQgYSBsb2FuLgoKYGBge3IsIGVjaG89RkFMU0UsIFVuaXZhcmlhdGVfUGxvdHNfNywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZ2dwbG90KGFlcyh4ID0gUHJvc3BlclNjb3JlKSwgZGF0YSA9IGxvYW5zX2ZpbHRlcmVkKSArIAogIGdlb21fYmFyKGNvbG9yID0gKCcjMjQzMjNlJyksIGZpbGwgPSAoJyMwMmNjYmEnKSkgKwogIGdndGl0bGUoJ1Byb3NwZXIgc2NvcmUnKQoKc3VtbWFyeShsb2Fuc19maWx0ZXJlZCRQcm9zcGVyU2NvcmUpCmBgYAoKYGBge3IsIGVjaG89RkFMU0UsIFVuaXZhcmlhdGVfUGxvdHNfOCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZ2dwbG90KGFlcyh4ID0gQ3JlZGl0R3JhZGUpLCBkYXRhID0gbG9hbnNfZmlsdGVyZWQpICsgCiAgZ2VvbV9iYXIoY29sb3IgPSAoJyMyNDMyM2UnKSwgZmlsbCA9ICgnIzAyY2NiYScpKSArCiAgZ2d0aXRsZSgnQ3JlZGl0IGdyYWRlJykKYGBgCgpUaGUgcGxvdCBhYm92ZSBzaG93cyB0aGF0IHRoZXJlIGlzIG1vc3Qgb2YgdGhlIGRhdGEgZm9yIGNyZWRpdCBncmFkZSBtaXNzaW5nLgoKYGBge3IsIGVjaG89RkFMU0UsIFVuaXZhcmlhdGVfUGxvdHNfOSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZ2dwbG90KGFlcyh4ID0gRW1wbG95bWVudFN0YXR1c0R1cmF0aW9uKSwgZGF0YSA9IGxvYW5zX2ZpbHRlcmVkKSArIAogIGdlb21faGlzdG9ncmFtKGNvbG9yID0gKCcjMjQzMjNlJyksIGZpbGwgPSAoJyMwMmNjYmEnKSkgKwogIGdndGl0bGUoJ0VtcGxveW1lbnQgc3RhdHVzIGR1cmF0aW9uIGluIG1vbnRocycpCmBgYAoKV2UgY2FuIHNlZSB0aGF0IHRoZSBsb25nZXIgcGVvcGxlIGhhdmUgYW4gZW1wbG95bWVudCB0aGUgbGVzcyB0aGV5IG5lZWQgYSBsb2FuLiAKCmBgYHtyLCBlY2hvPUZBTFNFLCBVbml2YXJpYXRlX1Bsb3RzXzEwLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpnZ3Bsb3QoZGF0YSA9IGxvYW5zX2ZpbHRlcmVkLCBhZXMoeCA9IERlYnRUb0luY29tZVJhdGlvKSkgKyAgICAgICAgICAgICAgICAKICAgICAgICBnZW9tX2hpc3RvZ3JhbShjb2xvdXIgPSAnIzI0MzIzZScsIGZpbGwgPSAnIzAyY2NiYScsIGJpbndpZHRoID0gMC4wMDUpICsKICAgICAgICB4bGltKDAsIHF1YW50aWxlKGxvYW5zX2ZpbHRlcmVkJERlYnRUb0luY29tZVJhdGlvLCBwcm9iID0gMC41LCBuYS5ybSA9IFRSVUUpKSArCiAgICAgICAgZ2d0aXRsZSgiRGVidCBUbyBJbmNvbWUgUmF0aW8iKSArCiAgICAgICAgeGxhYigiRGVidCB0byBJbmNvbWUgUmF0aW8iKSArCiAgICAgICAgeWxhYigiQ291bnQiKQogICAgICAgIHN1bW1hcnkobG9hbnNfZmlsdGVyZWQkbG9hbl9pbmNvbWVfcmF0aW8pCmBgYCAKCmBgYHtyLCBlY2hvPUZBTFNFLCBVbml2YXJpYXRlX1Bsb3RzXzExLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpnZ3Bsb3QoYWVzKHggPSBMZW5kZXJZaWVsZCksIGRhdGEgPSBsb2Fuc19maWx0ZXJlZCkgKyAKICBnZW9tX2hpc3RvZ3JhbShjb2xvciA9ICgnIzI0MzIzZScpLCBmaWxsID0gKCcjMDJjY2JhJykpICsKICBnZ3RpdGxlKCdMZW5kZXIgWWllbGQnKQpgYGAKCmBgYHtyLCBlY2hvPUZBTFNFLCBVbml2YXJpYXRlX1Bsb3RzXzEyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpnZ3Bsb3QoYWVzKHggPSBsb2Fuc19maWx0ZXJlZCRJbnZlc3RvcnMsIHkgPSAuLmNvdW50Li4pLCBkYXRhID0gbG9hbnNfZmlsdGVyZWQpICsKICBnZW9tX2ZyZXFwb2x5KGFlcyhjb2xvciA9IEludmVzdG9ycyksIGJpbndpZHRoPTAuMSkgKyAKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCAyNTApLCBicmVha3MgPSBzZXEoMCwgNTAsIDI1MCkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDc1MCwgNTApKSsKICB5bGltKDAsIDc1MCkrCiAgeGxpbSgxLCAyNTApKwogIHhsYWIoJ051bWJlciBvZiBJbnZlc3RvcnMnKSArIAogIHlsYWIoJ2NvdW50JykgKwogIGdndGl0bGUoJ051bWJlciBvZiBJbnZlc3RvcnMgcGVyIExvYW4nKQpgYGAKClRoZSBtYWpvcml0eSBvZiB0aGUgSW52ZXN0b3JzIGlzIGp1c3Qgb25lIHBlcnNvbi4gSW4gdGhlIHBsb3QgYWJvdmUsIHdlIGxpbWl0IHRoZSBudW1iZXIgb2YgbG9hbnMgZ2l2ZW4gdG8gNzYwIGluIG9yZGVyIHRvIGdldCBhIGJldHRlciBwaWN0dXJlIG9mIGxvYW5zIGdpdmVuIGJ5IG1vcmUgdGhlbiBvbmUgaW52ZXN0b3IuICAKCiMgVW5pdmFyaWF0ZSBBbmFseXNpcwoKIyMjIFN0cnVjdHVyZSBvZiB0aGUgZGF0YXNldApUaGlzIGRhdGEgc2V0IGNvbnRhaW5zIDExMyw5MzcgbG9hbnMgd2l0aCA4MiB2YXJpYWJsZXMgb24gZWFjaCBsb2FuLgpJbmNsdWRpbmcgbG9hbiBhbW91bnQsIGJvcnJvd2VyIHJhdGUgKG9yIGludGVyZXN0IHJhdGUpLCBjdXJyZW50IGxvYW4gc3RhdHVzLCBib3Jyb3dlciBpbmNvbWUsIGJvcnJvd2VyIGVtcGxveW1lbnQgc3RhdHVzLCBib3Jyb3dlciBjcmVkaXQgaGlzdG9yeSwgYW5kIHRoZSBsYXRlc3QgcGF5bWVudCBpbmZvcm1hdGlvbi4KVGhlIGV4cGxhbmF0aW9uIG9mIHRoZSB2YXJpYWJsZXMgY2FuIGJlIGZvdW5kIHRoZXJlOiBodHRwczovL3d3dy5wcm9zcGVyLmNvbS9Eb3dubG9hZHMvU2VydmljZXMvRG9jdW1lbnRhdGlvbi9Qcm9zcGVyRGF0YUV4cG9ydF9EZXRhaWxzLmh0bWwKCiMjIyBNYWluIGZlYXR1cmVzIG9mIGludGVyZXN0IGluIHRoZSBkYXRhc2V0CldlIHdhbnQgdG8ga25vdyBob3cgbXVjaCBtb25leSBpcyBuZWVkZWQsIHdoZW4gYW5kIHdoeS4gU28gdGhlIG1vc3QgaW1wb3J0YW50IHZhcmlhYmxlcyBhcmUgJ09yaWdpbmFsTG9hbkFtb3VudCcsICdMb2FuT3JpZ2luYXRpb25EYXRlJyBhbmQgJ0NhdGVnb3J5Jy4KV2UgdGhpbmsgaXQgaXMgYWxzbyBpbnRlcmVzdGluZyB0byBzZWUgaWYgdGhlcmUgaXMgYSBkaWZmZXJlbmNlIGluIGxvYW4gdGFraW5nIGJldHdlZW4gaG9tZSBvd25lcnMgYW5kIG5vbiBob21lIG93bmVycy4gClRoZW4gd2UgYXJlIGFsc28gaW50ZXJlc3RlZCB0byBzZWUgaWYgdGhlIGNyZWRpdCBncmFkZSBhbmQgdGhlIHByb3NwZXIgc2NvcmUgYXJlIHJlbGF0ZWQgdG8gb3RoZXIgdmFyaWFibGVzLgoKIyMjIE1vcmUgZmVhdHVyZXMKQW5vdGhlciBwb2ludCBvZiBpbnRlcmVzdCBpcyB0aGUgbGVuZGVyIHlpZWxkLiBBbmQgd2UgYXJlIGFsb3MgY3VyaW91cyBhYm91dCB0aGUgZmVlcyB0aGF0IHRoZSBjb21wYW55IHRha2VzLgoKIyMjIE5ldyB2YXJpYWJsZXMKVG8gcHJvdmlkZSBhIGJldHRlciByZWFkYWJpbGl0eSB3ZSBjcmVhdGVkIHRoZSB2YXJpYWJsZSAiQ2F0ZWdvcnkiLCB3aGVyZSB3ZSBtYXBwZWQgdGhlIGNhdGVnb3JpZXMgdG8gdGhlIG51bWJlcnMgb2YgdGhlICdMaXN0aW5nQ2F0ZWdvcnkuLm51bWVyaWMnLgpXZSBhbHNvIGNyZWF0ZWQgYSBuZXcgdmFyaWFibGUgbmFtZWQgJ0dyb3VwZWRPY2N1cGF0aW9uJy4gQmVjYXVzZSB0aGUgb3JpZ2luYWwgdmFyaWFibGUgJ09jY3VwYXRpb24nIGNvbnNpdHMgb2YgNjggbGV2ZWxzLCB3ZSB3YW50ZWQgdG8gZ3JvdXAgdGhvc2UgdG8gZ2V0IGEgYmV0dGVyIG92ZXJ2aWV3LiBUaGUgbmV3IHZhcmlhYmxlIGNvbnNpdHMgb2YgOCBsZXZlbHMgcmVwcmVzZW50aW5nIG91ciBvY2N1cGF0aW9uYWwgZ3JvdXBzLgoKIyMjIENoYW5nZWQgdmFyaWFibGVzCkluIHRoZSBMb2FuT3JpZ2luYWxBbW91bnQgdmFyaWFibGUgd2UgcGVyZm9yZW1lZCBhbiBvdXRsaWVyIGNoZWNrIGFuZCByZW1vdmVkIHRob3NlIHZhbHVlcyBpbiBvcmRlciB0byBtYWtlIHRoZSBmb2xsb3dpbmcgYW5hbHlzaXMgbW9yZSByb2J1c3QuCgoKIyBCaXZhcmlhdGUgUGxvdHMgU2VjdGlvbgoKTm8gd2Ugd2FudCB0byB0YWtlIGEgbG9vayBhdCB0aGUgaG9tZSBvd25lcnMuCkluIHRoZSBuZXh0IHN0ZXAgd2Ugd2FudCB0byBwcm9vZiB0aGF0IHBlb3BsZSB3aG8gYXJlbiB0IGhvbWUgb3duZXJzIG5lZWQgbW9yZSBvZnRlbiBzbWFsbCBsb2FucyBmb3IgdmFjYXRpb24sIGhvbWUgaW1wcm92ZW1lbnQgb3IgaG91c2Vob2xkIGV4cGVuc2VzIHRoYW4gaG9tZSBvd25lcnMuIE91ciBzdWdnZXN0aW9uIHRoYXQgaG91c2Ugb3duZXJzIG5lZWQgbGVzcyBsb2Fucywgc2VlbSB0byBiZSB3cm9uZy4gQWxtb3N0IGhhbGYgdGhlIGFtb3VudCBvZiBib3Jyb3dlcnMgYXJlIGhvdXNlIG93bmVycy4KV2UgbGltaXQgdGhlIGxvYW4gYW1vdW50IHRvIGEgc21hbGxlciByYW5nZSwgYmVjYXVzZSB3ZSB3YW50IHRvIGtub3cgaWYgaG91c2Ugb3duZXJzIGFsc28gbmVlZCBzbWFsbGVyIGxvYW5zLCBmb3IgaG9tZSBpbXByb3ZtZW50cyBvciBvdGhlcnMuCgpgYGB7ciwgZWNobz1GQUxTRSwgQml2YXJpYXRlX1Bsb3RzXzEsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiAgcXBsb3QoeCA9IElzQm9ycm93ZXJIb21lb3duZXIsIHkgPSBMb2FuT3JpZ2luYWxBbW91bnQsCiAgICAgICAgZGF0YSA9IGxvYW5zX2ZpbHRlcmVkLCBnZW9tID0gJ2JveHBsb3QnKSArCiAgIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDEwMDAsIDIwMDAwKSkgKwogICBnZ3RpdGxlKCdIb21lIG93bmVyIGJ5IGxpbWl0ZWQgbG9hbiBvcmlnaW5hbCBhbW91bnQnKQpgYGAKCkluIHRoZSBwbG90IGFib3ZlIHdlIGNhbiBzZWUgdGhhdCBob3VzZSBvd25lcnMgbmVlZCBiaWdnZXIgYW1vdW50cyBvZiBtb25leSB0aGFuIG5vbiBob3VzZSBvd25lcnMuCgpOZXh0IHdlIHdhbnQgdG8gc2VlLCBpZiB0aGVyZSBpcyBhIHJlbGF0aW9uIGJldHdlZW4gdGhlIHByb3NwZXIgcmF0ZSBhbmQgdGhlIGZhY3QgdGhhdCB0aGUgYm9ycm93ZXIgaXMgYSBob3VzZSBvd25lci4gTm9ybWFsbHkgYSBob3VzZSBvd25lciBoYXMgYSBiZXR0ZXIgcmF0aW5nLCBkdWUgdG8gbW9yZSBmaW5hbmNpYWwgc2VjdXJpdHkuCgpgYGB7ciwgZWNobz1GQUxTRSwgQml2YXJpYXRlX1Bsb3RzXzIsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiBnZ3Bsb3QoYWVzKGZhY3RvcihJc0JvcnJvd2VySG9tZW93bmVyKSwgCiAgICAgICAgICAgIFByb3NwZXJTY29yZSksIAogICAgICAgIGRhdGEgPSBsb2Fuc19maWx0ZXJlZCkgKwogIGdlb21faml0dGVyKCBhbHBoYSA9IC4zKSAgKwogIGdlb21fYm94cGxvdCggYWxwaGEgPSAuNSxjb2xvciA9ICcjMDJjY2JhJykrCiAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gJ21lYW4nLCAKICAgICAgICAgICAgICAgZ2VvbSA9ICdwb2ludCcsIAogICAgICAgICAgICAgICBjb2xvciA9ICcjMjQzMjNlJywgCiAgICAgICAgICAgICAgIHNoYXBlID0gOCwgCiAgICAgICAgICAgICAgIHNpemUgPSA0KSsKICBnZ3RpdGxlKCdIb21lIG93bmVyIGJ5IHByb3NwZXIgc2NvcmUnKQpgYGAKCkFub3RoZXIgc3VycHJpc2UgaGVyZS4gVGhlIFByb3NwZXIgc2NvcmUgZm9yIG5vbiBob21lIG93bmVycyBpcyBqdXN0IGEgbGl0dGxlIGJpdCBsb3dlci4gCgpgYGB7ciwgZWNobz1GQUxTRSwgQml2YXJpYXRlX1Bsb3RzXzMsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnN1bW1hcnkobG9hbnNfZmlsdGVyZWQkTW9udGhseUxvYW5QYXltZW50KQpnZ3Bsb3QoYWVzKHg9Q3VycmVudERlbGlucXVlbmNpZXMsIHk9Li5jb3VudC4uL3N1bSguLmNvdW50Li4pKSwgZGF0YSA9IHN1YnNldChsb2Fuc19maWx0ZXJlZCwgIWlzLm5hKElzQm9ycm93ZXJIb21lb3duZXIpKSkgKwogIGdlb21fZnJlcXBvbHkoYWVzKGNvbG9yID0gSXNCb3Jyb3dlckhvbWVvd25lcikpICsgCiAgeGxhYignQ3VycmVudERlbGlucXVlbmNpZXMnKSArIAogIHlsYWIoJ1BlcmNlbnRhZ2Ugb2YgQm9ycm93ZXJzIHdpdGggY3VycmVudCBkZWxpbnF1ZW5jaWVzJykgKwogIGdndGl0bGUoJ0N1cnJlbnQgZGVsaW5xdWVuY2llcyBieSBob21lIG93bmVyJykKYGBgCgpJbiB0aGUgcGxvdCBhYm92ZSB3ZSBjYW4gbm90IG5vdGljZSBhbnkgZGlmZmVyZW5jZSBiZXR3ZWVuIGhvbWUgb3duZXJzIGFuZCBub24gaG9tZSBvd25lcnMgaW4gY3VycmVudCBkZWxpbnF1ZW5jaWVzLgoKYGBge3IsIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMtLS0tLS0tLS0tLS0tLS0tLWNyZWF0ZSBhIG5ldyBERiB3aXRoIGluZm8gYWJvdXQgdGhlIHByb3NwZXIgcmF0aW5nIGFuZCB0aGUgYW1vdW50CmNyZWRpdHNCeUdyYWRlIDwtIGdyb3VwX2J5KGxvYW5zLCBQcm9zcGVyUmF0aW5nLi5udW1lcmljLikKY3JlZGl0c0J5R3JhZGUgPC0gc3VtbWFyaXNlKGNyZWRpdHNCeUdyYWRlLAogICAgbWVhbl9hbW91bnQgPSBtZWFuKExvYW5PcmlnaW5hbEFtb3VudCksIAogICAgbWVkaWFuX2Ftb3VudCA9IG1lZGlhbihMb2FuT3JpZ2luYWxBbW91bnQpLAogICAgbWluX2Ftb3VudCA9IG1pbihMb2FuT3JpZ2luYWxBbW91bnQpLAogICAgbWF4X2Ftb3VudCA9IG1heChMb2FuT3JpZ2luYWxBbW91bnQpLAogICAgbiA9IG4oKSkgCgpjcmVkaXRzQnlHcmFkZQpgYGAKCmBgYHtyLCBlY2hvPUZBTFNFLCBCaXZhcmlhdGVfUGxvdHNfNCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZ2dwbG90KGFlcyh4PUJvcnJvd2VyUmF0ZSwgeT1Qcm9zcGVyU2NvcmUpLCBkYXRhID0gbG9hbnNfZmlsdGVyZWQpKwogIGdlb21fcG9pbnQoYWxwaGEgPSAxLzUsIGNvbG91ciA9ICcjMDJjY2JhJykrCiAgZ2VvbV9zbW9vdGgoKSsKICBnZ3RpdGxlKCJMaW5lIFBsb3Qgb2YgYm9ycm93ZXIgcmF0ZSBhbmQgcHJvc3BlciBzY29yZSIpCmBgYAoKTm8gc3VycHJpc2VzIGhlcmUsIHRoZSBiZXR0ZXIgdGhlIFByb3NwZXIgU2NvcmUsIHRoZSBiZXR0ZXIgdGhlIGJvcnJvd2VyIHJhdGUuCgpXZSBzdWdnZXN0IHRoYXQgdGhlIHByb3NwZXIgcmF0aW5nIGlzIGJldHRlciBpZiB0aGUgaW5jb21lIGlzIHZlcmlmaWFibGUuCmBgYHtyLCBlY2hvPUZBTFNFLCBCaXZhcmlhdGVfUGxvdHNfNSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZ2dwbG90KGFlcyh4ID0gUHJvc3BlclJhdGluZy4ubnVtZXJpYy4sIHkgPSAuLmNvdW50Li4vc3VtKC4uY291bnQuLikpLCBkYXRhID0gc3Vic2V0KGxvYW5zX2ZpbHRlcmVkLCAhaXMubmEoSW5jb21lVmVyaWZpYWJsZSkpKSArCiAgZ2VvbV9mcmVxcG9seShhZXMoY29sb3I9SW5jb21lVmVyaWZpYWJsZSkpICsgCiAgeGxhYignUHJvc3BlciBSYXRpbmcnKSArIAogIHlsYWIoJ1BlcmNlbnRhZ2Ugb2YgQm9ycm93ZXJzIHdpdGggdGhhdCBQcm9zcGVyIFJhdGluZycpKwogIGdndGl0bGUoIlByb3NwZXIgcmF0aW5nIGluIHBlcmNlbnQgYnkgdmVyaWZpYWJsZSBpbmNvbWUiKQpgYGAKWWVzLCBvdXIgc3VnZ2VzdGlvbiBpcyByaWdodC4KCmBgYHtyLCBlY2hvPUZBTFNFLCBCaXZhcmlhdGVfUGxvdHNfNiwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KICAgIHFwbG90KHg9Q3JlZGl0R3JhZGUsIHk9RGVsaW5xdWVuY2llc0xhc3Q3WWVhcnMsCiAgICAgICAgZGF0YT1sb2Fuc19maWx0ZXJlZCwgZ2VvbT0nYm94cGxvdCcpKwogICAgeWxpbSgwLCAyNSkgKwogIGdndGl0bGUoJ0N1cnJlbnQgZGVsaW5xdWVuY2llcyBieSBjcmVkaXQgZ3JhZGUnKQpgYGAKCkFzIHdlIGNhbiBzZWUgaW4gdGhlIHBsb3QgYWJvdmUsIHRoZSBiZXR0ZXIgdGhlIGNyZWRpdCBncmFkZSwgbGVzcyBkZWxpbnF1ZW5pY2VzLgoKYGBge3IsIGVjaG89RkFMU0UsIEJpdmFyaWF0ZV9QbG90c183LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpnZ3Bsb3QoZGF0YT1zdWJzZXQobG9hbnNfZmlsdGVyZWQsIENyZWRpdEdyYWRlICE9ICdOQycgJiBDcmVkaXRHcmFkZSAhPSAnJyAgJiAhaXMubmEoQ3JlZGl0R3JhZGUpICYgIWlzLm5hKEVtcGxveW1lbnRTdGF0dXMpICYgRW1wbG95bWVudFN0YXR1cyAhPSAnTm90IEF2YWlsYWJsZScgJiBFbXBsb3ltZW50U3RhdHVzICE9ICdPdGhlcicgJiBFbXBsb3ltZW50U3RhdHVzICE9ICcnKQogICxhZXMoeD1DcmVkaXRHcmFkZSwgeT1FbXBsb3ltZW50U3RhdHVzLCBmaWxsPUVtcGxveW1lbnRTdGF0dXMpKSArIAogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IikgKwogIHhsYWIoIkNyZWRpdCBncmFkZSIpICsKICB5bGFiKCJFbXBsb3ltZW50IHN0YXR1cyIpICsKICBnZ3RpdGxlKCdDcmVkaXQgZ3JhZGUgYnkgZW1wbG95bWVudCBzdGF0dXMnKQpgYGAKClRoZSBtYWpvcml0eSBvZiB0aGUgbG9hbiB0YWtlcnMgYXJlIGZ1bGwgdGltZSBlbXBsb3llZXMuIFRoZSB3b3JzZSB0aGUgY3JlZGl0IGdyYWRlIGdldHMgdGhlIG1vcmUgbGlrZWx5IHRoZSBlbXBsb3ltZW50IHN0YXR1cyBpcyAibm90IGF2YWlsYWJsZSIuIFdlIGV4Y2x1ZGUgbWlzc2luZyBkYXRhIGluIG91ciBwbG90LCB0byBnZXQgYSBnb29kIHBpY3R1cmUuCgpXZSBzdWdnZXN0IHRoYXQgdGhlcmUgaXMgYSBoaWdoZXIgbGVuZGVyIHlpZWxkLCBpZiB0aGUgYm9ycm93ZXIgcmF0ZSBpcyBoaWdoZXIuCmBgYHtyLCBlY2hvPUZBTFNFLCBCaXZhcmlhdGVfUGxvdHNfOCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZ2dwbG90KGxvYW5zLCBhZXMoeCA9IExlbmRlcllpZWxkLCB5ID0gQm9ycm93ZXJSYXRlKSkgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAxLzIwLCBjb2xvdXIgPSAnIzAyY2NiYScpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCBxdWFudGlsZShsb2FucyRMZW5kZXJZaWVsZCwgMC43NSkpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKCAKICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygwICwgcXVhbnRpbGUobG9hbnMkQm9ycm93ZXJSYXRlLCAwLjc1KSkpICsKICBnZ3RpdGxlKCdMZW5kZXIgeWllbGQgYW5kIGJvcnJvd2VyIHJhdGUnKQpgYGAKClllcywgd2UgY2FuIHNlZSBjbGVhcmx5IHRoZSBoaWdoZXIgdGhlIGJvcnJvd2VyIHJhdGUsIHRoZSBoaWdoZXIgdGhlIGxlbmRlciB5aWVsZC4KCiMgQml2YXJpYXRlIEFuYWx5c2lzCgpXZSBmb3VuZCBvdXQgdGhhdCB0aGVyZSBpcyBhbG1vc3Qgbm8gZGlmZmVyZW5jZSBiZXR3ZWVuIGhvbWUgb3duZXJzIGFuZCBub24gaG9tZSBvd25lcnMgYnkgcHJvc3BlciBzY29yZSBhbmQgZGVsaW5xdWVuY2llcy4gVGhlcmUgaXMgYSBzbGlnaHQgZGlmZmVyZW5jZSBhcyBob21lIG93bmVycyB0ZW5kIHRvIG5lZWQgYmlnZ2VyIGxvYW5zLgoKVGhlIHByb3NwZXIgcmF0aW5nIGlzIGJldHRlciBpZiB0aGUgaW5jb21lIGlzIHZlcmlmaWFibGUuIApUaGUgd29yc2UgdGhlIGNyZWRpdCBncmFkZSB0aGUgbW9yZSBvZnRlbiBvY2N1cmVkIGRlbGlucXVlbmNpZXMgaW4gdGhlIGxhc3QgNyB5ZWFycy4KCldlIG5vdGljZSBhIHN0cm9uZyByZWxhdGlvbiBiZXR3ZWVuIHRoZSBsZW5kZXIgeWllbGQgYW5kIHRoZSBib3Jyb3dlciByYXRlLiBUaGUgaGlnaGVyIHRoZSBib3Jyb3dlciByYXRlLCB0aGUgYmV0dGVyIHRoZSBsZW5kZXIgeWllbGQuCgojIE11bHRpdmFyaWF0ZSBQbG90cyBTZWN0aW9uCgpgYGB7ciwgZWNobz1GQUxTRSwgTXVsdGl2YXJpYXRlX1Bsb3RzXzEsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgQ29udmVydCBkYXRlIHRvIHllYXIgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCmxvYW5zX2ZpbHRlcmVkJExvYW5PcmlnaW5hdGlvblllYXIgPC0gZm9ybWF0KGFzLkRhdGUobG9hbnNfZmlsdGVyZWQkTG9hbk9yaWdpbmF0aW9uRGF0ZSwgZm9ybWF0PSIlWS0lbS0lZCIpLCIlWSIpCgpnZ3Bsb3QoYWVzKHggPSBMb2FuT3JpZ2luYXRpb25ZZWFyLCAKICAgICAgICAgICB5ID0gTG9hbk9yaWdpbmFsQW1vdW50LCAKICAgICAgICAgICBmaWxsID0gZmFjdG9yKFRlcm0pKSwKICAgICAgICBkYXRhID0gbG9hbnNfZmlsdGVyZWQpICsKICAgICAgICBnZW9tX2JveHBsb3QoKSsKICAgICAgICBnZ3RpdGxlKCJMb2FucyBieSBZZWFyIikgKwogICAgICAgIGxhYnMoeCA9ICJMb2FuIG9yaWdpbmF0aW9uIHllYXIiLCB5ID0gIkxvYW4gb3JpZ2luYWwgYW1vdW50IikKYGBgCgpJbiB0aGUgcGxvdCBhYm92ZSB3ZSBjYW4gc2VlIHRoYXQgZnJvbSAyMDA2IHRvIDIwMTAgdGhlIGxvYW5zIHdoZXJlIHRha2VuIGZvciAzNiBtb250aC4gTWF5YmUgYmFjayB0aGFuIHRoaXMgd2FzIHRoZSBvbmx5IHRlcm0gYXZhaWxhYmxlLiBGcm9tIDIwMTAgb24gaWYgdGhlIGxvYW4gYW1vdW50IHdhcyBoaWdoZXIgYm9ycm93ZXJzIHNlbGVjdGVkIHRoZSA2MCBtb250aCB0ZXJtLiBJbiAyMDExIHRoZSBsb2FucyBpbmNyZWFzZWQgYSBsb3QuCgpgYGB7ciwgZWNobz1GQUxTRSwgTXVsdGl2YXJpYXRlX1Bsb3RzXzIsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmdncGxvdChhZXMoeD0gZmFjdG9yKEdyb3VwZWRPY2N1cGF0aW9uKSwgCiAgICAgICAgICAgeT0gTG9hbk9yaWdpbmFsQW1vdW50LCAKICAgICAgICAgICBmaWxsID1Jc0JvcnJvd2VySG9tZW93bmVyKSwgCiAgICAgICAgZGF0YSA9IHN1YnNldChsb2Fuc19maWx0ZXJlZCwgIWlzLm5hKEdyb3VwZWRPY2N1cGF0aW9uKSAmIChHcm91cGVkT2NjdXBhdGlvbiAhPSAnT3RoZXInKSkpICsKICAgICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT00NSxoanVzdD0wLjUsdmp1c3Q9MC41KSkrCiAgIGdlb21fYm94cGxvdCggYWxwaGEgPSAuNSApICsKICBnZ3RpdGxlKCJMb2FuIGFtb3VudCBieSBncm91cGVkIG9jY3VwYXRpb24gYW5kIGhvbWVvd25lciBzdGF0dXMiKQpgYGAKCkluIHRoZSBmYWN0b3IgcGxvdCBhYm92ZSwgd2UgY2FuIHNlZSB0aGF0IHN0dWRlbnRzIG5lZWQgdGhlIHNtYWxsZXIgYW1vdW50cyBvZiBtb25leS4gVGhlIGhpZ2hlciB0aGUgbG9hbiBnZXRzLCB0aGUgbW9yZSBob21lb3duZXJzIGFyZSB0aGUgYm9ycm93ZXJzLgoKYGBge3IsIGVjaG89RkFMU0UsIE11bHRpdmFyaWF0ZV9QbG90c18zLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpnZ3Bsb3QoYWVzKHggPSBMb2FuT3JpZ2luYWxBbW91bnQsIGZpbGwgPSBMb2FuU3RhdHVzKSwgZGF0YSA9IGxvYW5zX2ZpbHRlcmVkKSArCiAgICBmYWNldF93cmFwKH5UZXJtKSArCiAgICBnZW9tX2hpc3RvZ3JhbShhZXMoY29sb3IgPSBMb2FuU3RhdHVzKSkgKwogICAgc2NhbGVfZmlsbF9icmV3ZXIodHlwZSA9ICdxdWFsJykgKwogICAgZ2d0aXRsZSgiSGlzdG9ncmFtIG9mIGxvYW4gQW1vdW50cyBieSBzdGF0dXMgYW5kIHRlcm1zIikKYGBgCgpJbiB0aGUgcGxvdCBhYm92ZSB3ZSBjYW4gc2VlIHRoYXQgbW9zdCBvZiB0aGUgbG9hbnMgYXJlIG1pZC10ZXJtLiAKCmBgYHtyIGVjaG89RkFMU0UsIE11bHRpdmFyaWF0ZV9QbG90c180LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpnZ3Bsb3QoYWVzKHggPSBCb3Jyb3dlclJhdGUsIHkgPSBJbnZlc3RvcnMpLCBkYXRhPWxvYW5zX2ZpbHRlcmVkKSArIAogIGdlb21fcG9pbnQoYWVzKGNvbG9yPUxlbmRlcllpZWxkKSkrCiAgeWxpbSgwLCA2MDApKwogIGdndGl0bGUoJ0xlbmRlciB5aWVsZCBieSBudW1iZXIgb2YgaW52ZXN0b3JzJykKYGBgCgpJbiB0aGUgcGxvdCBhYm92ZSB3ZSBjYW4gc2VlIHF1aXRlIHdlbGwsIHRoYXQgdGhlIGludmVzdG9ycyB5aWVsZCBnZXRzIGhpZ2hlciB0aGUgaGlnaGVyIHRoZSBib3Jyb3dlciByYXRlIGdldHMuCgpgYGB7ciBlY2hvPUZBTFNFLCBNdWx0aXZhcmlhdGVfUGxvdHNfNSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZ2dwbG90KGFlcyh4ID0gVGVybSwgeSA9IExvYW5PcmlnaW5hbEFtb3VudCksIGRhdGEgPSBsb2Fuc19maWx0ZXJlZCkgKwogICAgZmFjZXRfd3JhcCh+R3JvdXBlZE9jY3VwYXRpb24pICsKICAgIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gQ2F0ZWdvcnkpKSArCiAgICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygxMDAwLCA1MDAwKSkgKyAKICBnZ3RpdGxlKCdMb2FuIGFtb3VudCBieSB0ZXJtLCBncm91cGVkIGJ5IGdyb3VwZWQgb2NjdXBhdGlvbiBhbmQgY2F0ZWdvcnknKQpgYGAKClRoZSBwbG90IGFib3ZlIGdpdmVzIHVzIGEgbmljZSBvdmVydmlldy4gQXMgd2UgY2FuIHNlZSBtb3N0IG9mIHRoZSBsb2FucyBhcmUgbWlkIHRlcm0gbG9hbnMgd2l0aCBhIGR1cmF0aW9uIG9mIDM2IG1vbnRoLiBUaGUgdXNhZ2VzIG9mIHRoZSBsb2FucyBhcmUgd2VsbCBtaXhlZC4gCgpgYGB7ciBlY2hvPUZBTFNFLCBNdWx0aXZhcmlhdGVfUGxvdHNfNiwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZ2dwbG90KGFlcyhFc3RpbWF0ZWRSZXR1cm4sIEVzdGltYXRlZExvc3MpLCAKICAgICAgIGRhdGE9c3Vic2V0KGxvYW5zX2ZpbHRlcmVkLCBHcm91cGVkT2NjdXBhdGlvbiAhPSAnT3RoZXInIAogICAgICAgICAgICAgICAgICAgJiAhaXMubmEoR3JvdXBlZE9jY3VwYXRpb24pCiAgICAgICAgICAgICAgICAgICAmICFpcy5uYShJbmNvbWVSYW5nZSkKICAgICAgICAgICAgICAgICAgICYgSW5jb21lUmFuZ2UgIT0gJ05vdCBkaXNwbGF5ZWQnCiAgICAgICAgICAgICAgICAgICYgSW5jb21lUmFuZ2UgIT0gJ05vdCBlbXBsb3llZCcpKSsKICBnZW9tX3BvaW50KGFlcyhzaXplPUluY29tZVJhbmdlLCBjb2xvdXI9R3JvdXBlZE9jY3VwYXRpb24pKSsKICBnZ3RpdGxlKCdFc3RpbWF0ZWQgbG9zcyBhbmQgZXN0aW1hdGVkIHJldHVybiBieSBpbmNvbWUgcmFuZ2Ugb2YgYm9ycm93ZXInKQpgYGAKClRoZSBwbG90IGFib3ZlIGdpdmVzIGFuIG92ZXJ2aWV3IG9mIHRoZSBlc3RpbWF0ZWQgcmV0dXJuIGFuZCBlc3RpbWF0ZWQgbG9zcyBieSBncm91cGVkIG9jY3VwYXRpb24gYW5kIGluY29tZSByYW5nZS4gQXMgdGhlcmUgaXMgdG8gbXVjaCBpbmZvcm1hdGlvbiBpbiB0aGUgcGxvdCwgd2UgaGFyZGx5IGNhbiBzZWUgYW55dGhpbmcuIFNvIHdlIGFyZSBnb2luZyB0byBzcGxpdCB0aGlzIGludG8gdHdvIHBsb3RzLgoKYGBge3IgZWNobz1GQUxTRSwgTXVsdGl2YXJpYXRlX1Bsb3RzXzcsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnBsb3QxIDwtIGdncGxvdChhZXMoRXN0aW1hdGVkUmV0dXJuLCBFc3RpbWF0ZWRMb3NzKSwgCiAgICAgICBkYXRhPXN1YnNldChsb2Fuc19maWx0ZXJlZCwgR3JvdXBlZE9jY3VwYXRpb24gIT0gJ090aGVyJyAKICAgICAgICAgICAgICAgICAgICYgIWlzLm5hKEdyb3VwZWRPY2N1cGF0aW9uKQogICAgICAgICAgICAgICAgICAgJiAhaXMubmEoSW5jb21lUmFuZ2UpCiAgICAgICAgICAgICAgICAgICAmIEluY29tZVJhbmdlICE9ICdOb3QgZGlzcGxheWVkJwogICAgICAgICAgICAgICAgICAmIEluY29tZVJhbmdlICE9ICdOb3QgZW1wbG95ZWQnKSkrCiAgZ2VvbV9wb2ludChhZXMoY29sb3VyPUdyb3VwZWRPY2N1cGF0aW9uKSkrCiAgZ2d0aXRsZSgnRXN0aW1hdGVkIGxvc3MgYW5kIGVzdGltYXRlZCByZXR1cm4gYnkgZ3JvdXBlZCBvY2N1cGF0aW9uJykKcGxvdDIgPC0gIGdncGxvdChhZXMoRXN0aW1hdGVkUmV0dXJuLCBFc3RpbWF0ZWRMb3NzKSwgCiAgICAgICBkYXRhPXN1YnNldChsb2Fuc19maWx0ZXJlZCwgR3JvdXBlZE9jY3VwYXRpb24gIT0gJ090aGVyJyAKICAgICAgICAgICAgICAgICAgICYgIWlzLm5hKEdyb3VwZWRPY2N1cGF0aW9uKQogICAgICAgICAgICAgICAgICAgJiAhaXMubmEoSW5jb21lUmFuZ2UpCiAgICAgICAgICAgICAgICAgICAmIEluY29tZVJhbmdlICE9ICdOb3QgZGlzcGxheWVkJwogICAgICAgICAgICAgICAgICAmIEluY29tZVJhbmdlICE9ICdOb3QgZW1wbG95ZWQnKSkrCiAgZ2VvbV9wb2ludChhZXMoY29sb3VyPUluY29tZVJhbmdlKSkrCiAgZ2d0aXRsZSgnRXN0aW1hdGVkIGxvc3MgYW5kIGVzdGltYXRlZCByZXR1cm4gYnkgaW5jb21lIHJhbmdlIG9mIGJvcnJvd2VyJykKZ3JpZC5hcnJhbmdlKHBsb3QxLCBwbG90MiwgbmNvbD0yKQpgYGAKClRoZSBwbG90cyBhYm92ZSBhcmUgc3RpbGwgbm90IHJlYWRhYmxlLiBTbyBpbiB0aGUgbmV4dCBwbG90IHdlIHdhbnQgdG8gZm9jdXMgb24gb24gc3BlY2lmaWMgb2NjdXBhdGlvbiBncm91cCBhbmQgdGhlIGVzdGltYXRlZCBsb3NzZXMgYW5kIHJldHVybnMuCgpgYGB7ciBlY2hvPUZBTFNFLCBNdWx0aXZhcmlhdGVfUGxvdHNfOCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZ2dwbG90KGFlcyhFc3RpbWF0ZWRSZXR1cm4sIEVzdGltYXRlZExvc3MpLCAKICAgICAgIGRhdGE9c3Vic2V0KGxvYW5zX2ZpbHRlcmVkLCBHcm91cGVkT2NjdXBhdGlvbiA9PSAnU3R1ZGVudCcgCiAgICAgICAgICAgICAgICAgICAmICFpcy5uYShHcm91cGVkT2NjdXBhdGlvbikKICAgICAgICAgICAgICAgICAgICYgIWlzLm5hKEluY29tZVJhbmdlKQogICAgICAgICAgICAgICAgICAgJiBJbmNvbWVSYW5nZSAhPSAnTm90IGRpc3BsYXllZCcKICAgICAgICAgICAgICAgICAgJiBJbmNvbWVSYW5nZSAhPSAnTm90IGVtcGxveWVkJykpKwogIGdlb21fcG9pbnQoYWVzKGNvbG91cj1JbmNvbWVSYW5nZSwgc2l6ZT1JbmNvbWVSYW5nZSkpKwogIGdndGl0bGUoJ0VzdGltYXRlZCBsb3NzIGFuZCBlc3RpbWF0ZWQgcmV0dXJuIGJ5IGluY29tZSByYW5nZSBvZiBzdHVkZW50cycpCmBgYAoKYGBge3IgZWNobz1GQUxTRSwgTXVsdGl2YXJpYXRlX1Bsb3RzXzksIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmdncGxvdChsb2Fuc19maWx0ZXJlZCwgYWVzKExQX0N1c3RvbWVyUGF5bWVudHMsIExQX0ludGVyZXN0YW5kRmVlcykpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvdXIgPUxQX1NlcnZpY2VGZWVzKSwgc2l6ZSA9IDEpICsKICBjb29yZF9lcXVhbCgpKwogIGdndGl0bGUoJ0xQX0ludGVyZXN0YW5kRmVlcyBhbmQgTFBfQ3VzdG9tZXJQYXltZW50cyBieSBMUF9TZXJ2aWNlRmVlcycpCmBgYAoKVGhpcyBwbG90IHNob3dzIHRoYXQgdGhlIGxvd2VyIHRoZSBjdXN0b21lciBwYXltZW50cyBhcmUgdGhlIGxvd2VyIHRoZSBzZXJ2aWNlIGZlZXMgYW5kIGludGVyZXN0IGZlZXMgYXJlLgoKYGBge3IgZWNobz1GQUxTRSwgTXVsdGl2YXJpYXRlX1Bsb3RzXzEwLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpnZ3Bsb3QoZGF0YSA9IGxvYW5zX2ZpbHRlcmVkLCBhZXMoeCA9IENhdGVnb3J5LCB5ID0gR3JvdXBlZE9jY3VwYXRpb24pKSArCiAgZ2VvbV90aWxlKGFlcyhmaWxsID0gTG9hbk9yaWdpbmFsQW1vdW50KSkgKwogICAgICAgIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT02MCxoanVzdD0xLHZqdXN0PTAuOSkpICsKICBnZ3RpdGxlKCdMb2FucyBieSBPY2N1cGF0aW9uIGFuZCBDYXRlZ29yeScpCmBgYApJbiB0aGUgcGxvdCBhYm92ZSB3ZSBnZXQgYW4gb3ZlcnZpZXcgb2YgdGhlIGxvYW5zIGJ5IGNhdGVnb3J5IGFuZCBncm91cGVkIG9jY3VwYXRpb24uIEl0IGlzIHF1aXRlIGhhcmQgdG8gZmluZCBhIHBhdHRlcm4gb24gdGhlIGZpcnN0IHNpZ2h0LCBzbyBtYXliZSBhIG5vcm1hbCBsaXN0IHdvdWxkIGhhdmUgZG9uZSBhIGJldHRlciBqb2IuCgojIE11bHRpdmFyaWF0ZSBBbmFseXNpcwojIyMgRXN0aW1hdGVkIGxvc3MgYW5kIGVzdGltYXRlZCByZXR1cm4gYnkgaW5jb21lIHJhbmdlIGFuZCBncm91cGVkIG9jY3VwYXRpb24KV2UgcGxvdGVkIGFuIG92ZXJ2aWV3IG9mIHRoZSBlc3RpbWF0ZWQgcmV0dXJuIGFuZCB0aGUgZXN0aW1hdGVkIGxvc3MgYnkgZ3JvdXBlZCBvY2N1cGF0aW9uIGFuZCBpbmNvbWUgcmFuZ2UuIEJlY2F1c2UgdGhlIHBsb3Qgd2FzIHRvIGRlbnNlIGFuZCB1bnJlYWRhYmxlLCB3ZSBzcGxpdCBpdCB1cCBpbnRvIHR3byBwbG90cy4gT25lIGZvciB0aGUgaW5jb21lIHJhbmdlIGFuZCBvbmUgZm9yIHRoZSBvY2N1cGF0aW9uIGdyb3VwLiBCdXQgdGhpcyBwbG90IGlzIG5vdCB2ZXJ5IHJlYWRhYmxlIGVpdGhlci4gU28gd2UgZm9jdXNlZCBvbiBvbmUgb2NjdXBhdGlvbmwgZ3JvdXAgLSB0aGUgc3R1ZGVudHMuIFRoaXMgcGxvdCBpcyB3ZWxsIHJlYWRhYmxlLiBBbmQgaXQgd2FzIHF1aXRlIHN1cnByaXNpbmcgdGhhdCB0aGVyZSBpcyBvbmUgb3V0bGllciB3aXRoIGEgbmVnYXRpdmUgZXN0aW1hdGVkIHJldHVybiBhbmQgYSByZWFsbHkgaGlnaCBlc3RpbWF0ZWQgbG9zcy4gCiMjIyBIZWF0bWFwIG9mIGdyb3VwZWQgb2NjdXBhdGlvbiBhbmQgY2F0ZWdvcnkgYnkgbG9hbiBvcmlnaW5hbCBhbW91bnQKSXQgd2FzIGV4cGVjdGVkIHRoYXQgdGhpcyBoZWF0bWFwIGdpdmVzIGEgbml2ZSBvdmVydmlldyBvZiB0aGUgb2NjdXBhdGlvbnMgYW5kIGNhdGVnb3JpZXMuIFdlIHdlcmUgaG9waW5nIHRvIGZpbmQgcGF0dGVybnMgd2l0aCBvbmUgbG9vay4gQnV0IHRoaXMgaXMgbm90IHRoZSBjYXNlLCB5b3UgaGF2ZSB0byBlbGFib3JhdGUgdGhpcyBwbG90LiBNYXliZSBpdCB3b3VsZCBoYXZlIGJlZW4gYmV0dGVyIHRvIHByb3ZpZGUgYSBsaXN0IGluIHRoaXMgY2FzZS4KIyMjIExvYW5zIGFuZCBGZWVzCkZyb20gMjAwNiB0byAyMDEwIHRoZSBsb2FucyB3aGVyZSB0YWtlbiBmb3IgMzYgbW9udGguIE1heWJlIGJhY2sgdGhhbiB0aGlzIHdhcyB0aGUgb25seSB0ZXJtIGF2YWlsYWJsZS4gRnJvbSAyMDEwIG9uIGlmIHRoZSBsb2FuIGFtb3VudCB3YXMgaGlnaGVyIGJvcnJvd2VycyBzZWxlY3RlZCB0aGUgNjAgbW9udGggdGVybS4gSW4gMjAxMSB0aGUgbG9hbnMgaW5jcmVhc2VkIGEgbG90LgpXZSBmb3VuZCBvdXQgdGhhdCB0aGUgbG93ZXIgdGhlIGN1c3RvbWVyIHBheW1lbnRzIGFyZSB0aGUgbG93ZXIgdGhlIHNlcnZpY2UgZmVlcyBhbmQgaW50ZXJlc3QgZmVlcyBhcmUuCldoaWNoIGlzIG5vdCBhIHN1cnByaXNlLgoKIyBGaW5hbCBQbG90cyBhbmQgU3VtbWFyeQoKIyMjIExvYW4gYW1vdW50IGJ5IGdyb3VwZWQgb2NjdXBhdGlvbiBhbmQgaG9tZW93bmVyIHN0YXR1cwoKYGBge3IgZWNobz1GQUxTRSwgRmluYWxfUGxvdF8xLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpnZ3Bsb3QoYWVzKHg9IGZhY3RvcihHcm91cGVkT2NjdXBhdGlvbiksIAogICAgICAgICAgIHk9IExvYW5PcmlnaW5hbEFtb3VudCwgCiAgICAgICAgICAgZmlsbCA9SXNCb3Jyb3dlckhvbWVvd25lciksIAogICAgICAgIGRhdGEgPSBzdWJzZXQobG9hbnNfZmlsdGVyZWQsICFpcy5uYShHcm91cGVkT2NjdXBhdGlvbikgJiAoR3JvdXBlZE9jY3VwYXRpb24gIT0gJ090aGVyJykpKSArCiAgICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9NDUsaGp1c3Q9MC41LHZqdXN0PTAuNSkpKwogICBnZW9tX2JveHBsb3QoIGFscGhhID0gMC41ICkKYGBgCgojIyMgRGVzY3JpcHRpb24KSW4gdGhlIGZhY3RvciBwbG90IGFib3ZlLCB3ZSBjYW4gc2VlIHRoYXQgc3R1ZGVudHMgbmVlZCB0aGUgc21hbGxlciBhbW91bnRzIG9mIG1vbmV5LiBTdXJwcmlzaW5nbHkgdGhlcmUgYXJlIGEgbG90IG9mIGhvbWUgb3duZXJzIGluIHRoZSBncm91cCBzdHVkZW50LiBUaGUgaGlnaGVyIHRoZSBsb2FuIGdldHMsIHRoZSBtb3JlIGhvbWVvd25lcnMgYXJlIHRoZSBib3Jyb3dlcnMuCkluIHNvbWUgb2NjdXBhdGlvbmFsIGdyb3VwcyB0aGVyZSBhcmUgYSBsb3QgbW9yZSBob21lIG93bmVycy4gVGhpcyBtYXkgYmUgY2F1c2VkIGJ5IG91ciBvY2N1cGF0aW9uYWwgZ3JvdXBpbmcsIHdoaWNoIGNvbnRhaW5zIHByb2Zlc3Npb25zIHdpdGggYSB3aWRlIGluY29tZSByYW5nZS4gRm9yIGV4YW1wbGUgaW4gdGhlIGdyb3VwICdNZWRpY2FsX0hlYWx0aCcsIHRoZXJlIGFyZSBkb2N0b3JzIGFuZCBudXJzZXMgZXRjLgoKIyMjIEhpc3RvZ3JhbSBvZiBsb2FuIGFtb3VudHMgYnkgdGVybSBhbmQgbG9hbiBzdGF0dXMKCmBgYHtyIGVjaG89RkFMU0UsIEZpbmFsX1Bsb3RfMiwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZ2dwbG90KGFlcyh4ID0gTG9hbk9yaWdpbmFsQW1vdW50LCBmaWxsID0gTG9hblN0YXR1cyksIGRhdGEgPSBsb2Fuc19maWx0ZXJlZCkgKwogICAgZmFjZXRfd3JhcCh+VGVybSkgKwogICAgZ2VvbV9oaXN0b2dyYW0oYWVzKGNvbG9yID0gTG9hblN0YXR1cykpICsKICAgIHNjYWxlX2ZpbGxfYnJld2VyKHR5cGUgPSAncXVhbCcpICsKICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LGhqdXN0PTAuNSx2anVzdD0wLjUpKSsKCiAgICBnZ3RpdGxlKCJIaXN0b2dyYW0gb2YgbG9hbiBBbW91bnRzIGJ5IHN0YXR1cyBhbmQgdGVybXMiKQpgYGAKCiMjI0Rlc2NyaXB0aW9uCkluIHRoZSBwbG90IGFib3ZlIHdlIGNhbiBzZWUgdGhhdCBtb3N0IG9mIHRoZSBwbG90cyBhcmUgdGFrZW4gd2l0aCBhIHRlcm1hIG9mIDM2IG1vbnRoLiBFdmVuIHRob3VnaCB0aGUgYW1vdW50cyBhcmUgbm90IHRoYXQgYmlnLiBUaGlzIG1heSBiZSBiZWNhdXNlIHVudGlsIDIwMDkgdGhlcmUgd2hlcmUgb25seSBsb2FucyB3aXRoIGEgdGVybSBvZiAzNiBtb250aC4gVGhpcyBtYXkgYWxzbyBleHBsYWluIHdoeSB0aGUgbG9hbiBzdGF0dXMgaXMgY29tcGxldGVkIG9yIGNoYXJnZWQgb2ZmIGZvciB0aGUgbW9zdCBvZiB0aGUgbG9hbnMgdW5kZXIgNTAwMC4gV2UgY2FuIGFsc28gc2VlIHRoYXQgc2hvcnQgdGVybSBsb2FucyBhcmUgbm90IG9mdGVuIHVzZWQgYXQgdGhlIG1vbWVudC4gUGVvcGxlIHByZWZlciBtaWQgb3IgbG9uZyB0ZXJtIGxvYW5zLiAKCgojIyMgRXN0aW1hdGVkIHJldHVybiBhbmQgZXN0aW1hdGVkIGxvc3MgZm9yIHN0dWRlbnRzCgpgYGB7ciBlY2hvPUZBTFNFLCBGaW5hbF9QbG90XzMsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmdncGxvdChhZXMoRXN0aW1hdGVkUmV0dXJuLCBFc3RpbWF0ZWRMb3NzKSwgCiAgICAgICBkYXRhPXN1YnNldChsb2Fuc19maWx0ZXJlZCwgR3JvdXBlZE9jY3VwYXRpb24gPT0gJ1N0dWRlbnQnIAogICAgICAgICAgICAgICAgICAgJiAhaXMubmEoR3JvdXBlZE9jY3VwYXRpb24pCiAgICAgICAgICAgICAgICAgICAmICFpcy5uYShJbmNvbWVSYW5nZSkKICAgICAgICAgICAgICAgICAgICYgSW5jb21lUmFuZ2UgIT0gJ05vdCBkaXNwbGF5ZWQnCiAgICAgICAgICAgICAgICAgICYgSW5jb21lUmFuZ2UgIT0gJ05vdCBlbXBsb3llZCcpKSsKICBnZW9tX3BvaW50KGFlcyhjb2xvdXI9SW5jb21lUmFuZ2UsIHNpemU9SW5jb21lUmFuZ2UpKSsKICBnZ3RpdGxlKCdFc3RpbWF0ZWQgbG9zcyBhbmQgZXN0aW1hdGVkIHJldHVybiBieSBpbmNvbWUgcmFuZ2Ugb2Ygc3R1ZGVudHMnKQoKCmBgYAoKIyMjRGVzY3JpcHRpb24KV2UgY2FuIHNlZSB0aGF0IG1vc3Qgb2YgdGhlIHN0dWRlbnRzIGVhcm4gYmV0d2VlbiAkMS0gMjQsOTk5LiBUaGVyZSBhcmUgc29tZSBzdHVkZW50cyB0aGF0IGEgZWFybiBtb3JlIHRoYW4gJDc1LDAwMC4gClRoZXJlIGFyZSBzb21lIG91dGxpZXJzIHdoZXJlIHRoZSBlc3RpbWF0ZWQgbG9zcyBpcyBoaWdoZXIgdGhhbiB0aGUgZXN0aW1hdGVkIHJldHVybi4gVGhlIG1ham9yaXR5IG9mIHRoZSBlc3RpbWF0ZWQgcmV0dXJucyBhbmQgZXN0aW1hdGVkIGxvc3NlcyBhcmUgYmV0dyBkZXBlbmRpbmcgb24gdGhlIGluY29tZSByYW5nZSBvZiBhIHN0dWRlbnQgYXJlIGJldHdlZW4gMC4wNSBhbmQgMC4xNS4gU3VycHJpc2luZ2x5IHRoZXJlIGlzIG9uZSBvdXRsaWVyIHdpdGggYSBuZWdhdGl2ZSBlc3RpbWF0ZWQgcmV0dXJuIGFuZCBhIHJlYWxseSBoaWdoIGVzdGltYXRlZCBsb3NzLiAKCiMjU3VtbWFyeQpCZWNhdXNlIG9mIHRoZSBiaWcgYW1vdW50IG9mIHZhcmlhYmxlcyBpdCB0b29rIHNvbWUgdGltZSwgdG8gcmVhZCB0aHJvdWdoIHRoZSBleHBsYW5hdGlvbnMgb2YgdGhlIHByb3NwZXIgbG9hbiBkYXRhLiBUbyBnZXQgc3RhcnRlZCB3ZSBleHBsb3JlZCBzb21lIGRpZmZlcmVudCB2YXJpYWJsZXMuIApJbiBvcmRlciB0byBnZXQgbmljZSBwbG90cywgd2UgaGFkIHRvIGNvbnZlcnQgc29tZSB2YWx1ZXMuIEZvciBleGFtcGxlIHRoZSBvcmlnaW4gZGF0ZSB0byB5ZWFyLCB0aGUgbnVtZXJpYyBjYXRlZ29yaWVzIGludG8gcmVhZGFibGUgY2F0ZWdvcmllcyBhbmQgdGhlIGpvYiBkdXJhdGlvbiBtb250aHMgd2hlcmUgc3VtbWFyaXplZCBpbiBidWNrZXRzCkl0IHdhcyBpbnRlcnJlc3RpbmcgdG8gc2VlIHRoYXQgZnJvbSAyMDExIG9uIGJvcnJvd2VycyBuZWVkZWQgaGlnaGVyIGxvYW5zIHdpdGggbG9uZ2VyIHRlcm1zLiAKSXQgd2FzIHF1aXRlIGEgc3VycHJpc2UgdGhhdCB0aGVyZSBpcyBubyBiaWcgZGlmZmVyZW5jZSBiZXR3ZWVuIGhvbWUgb3duZXJzIGFuZCBub24gaG9tZSBvd25lcnMsIGJlY2F1c2Ugd2Ugc3VnZ2VzdGVkIHRoYXQgaG9tZSBvd25lcnMgYXJlIGZpbmFuY2lhbGx5IG1vcmUgc3Ryb25nIGFuZCBkb24ndCBuZWVkIHNtYWxsIGxvYW5zLiAKRm9yIHRoZSBvdGhlciB2YXJpYWJsZXMgSSBjb3VsZCBub3QgZmluZCBhIGxvdCBvZiBzdXJwcmlzaW5nIGZhY3RzLiBGb3IgZXhhbXBsZSB0aGUgd29yc2UgdGhlIGNyZWRpdCBncmFkZSBpcywgdGhlIGhpZ2hlciB0aGUgZGVsaW5xdWVuY2llcyBpbiB0aGUgbGFzdCA3IHllYXJzIGFyZSBvciB0aGF0IHRoZSBsZW5kZXIgeWllbGQgZ2V0cyBsb3dlciB0aGUgaGlnaGVyIHRoZSBudW1iZSBvZiBpbnZlc3RvcnMgZ2V0LgpJdCB3b3VsZCBiZSBuaWNlIGlmIHRoZXJlIHdlcmUgbm90IGJpZyBncm91cHMgbGlrZSAnbmEnIG9yICdvdGhlcicgaW4gdGhlIG9jY3VwYXRpb24gYW5kIGNhdGVnb3J5IGdyb3VwLiBNYXliZSB0aGVyZSBjb3VsZCBiZSBhbHNvIGRhdGEgYWJvdXQgdGhlIGFnZSBhbmQgZ2VuZGVyIG9mIHRoZSBib3Jyb3dlciBwcm92aWRlZCwgd2hpY2ggbWF5IGxlYWQgdG8gaW50ZXJlc3RpbmcgZmluZGluZ3MuCg==